#include "StepByStep.h"

// Para1[0..Num1-1] <== Para2[0..Num2-1]
// Para1[j] = Para2[i] where j is the ParaIdx of Para2[i]
Bool ChangePara1ByPara2(int Num1, TypedList *Para1, int Num2, TypedList *Para2)
{
  TypedList *Pt;
  Bool      Change;
  int       i, j;

  Change = FALSE;
  for (i = 0; i < Num2; i++,Para2++) {
    j = Para2->VList.ParaIdx;
    if (j < 0 || j >= Num1) continue;

    Pt = Para1 + j;
    if (!EqualTwoVLists(&(Pt->VList), &(Para2->VList))) {
       CopyValueList(&(Pt->VList), &(Para2->VList));
       Change = TRUE;
    }
  }

  return Change;
}

//       Predication -- Para Of Pred
//                       ^^
//                       ||
//      ActKnowledge    Para Of ActK
void ModifyAllParentsByPC(PredKnowledge *PC)
{
  PredKnowledge *PC1;
  ActKnowledge  *ActK;
  int           Num1, Num2;

  ActK = PC->PAct;
  while (ChangeParaOfActionByPC(ActK, PC)) {
    for (PC1 = ActK->PC; PC1 != NULL; PC1 = PC1->next)
      ChangeOnePCByAction(PC1, ActK->Para);

    InstanceEffectOfAction(ActK);
    PC = ActK->Parent;

    Num1 = NumParaOfPred(PC->PredNo);
    Num2 = NumParaOfAct(ActK->ActNo);
    if (!ChangePara1ByPara2(Num1, PC->Para, Num2, ActK->Para)) break;

    ActK = PC->PAct;
  }
}

Bool ChangeParaOfPredByTypedList(PredKnowledge *PC, TypedList *Source)
{
  TypedList *Pt1, *Pt2;
  Bool       Change;
  int        i, Num;

  Pt1 = PC->Para;
  Pt2 = Source;
  Num = NumParaOfPred(PC->PredNo);
  for (i = 0; i < Num ; i++,Pt1++,Pt2++)
    if (Pt1->VList.NumValue > 0 && Pt2->VList.NumValue==0) return ERROR;

  Change = CopyTwoTypedLists(Num, PC->Para, Source);

  if (Change) ModifyAllParentsByPC(PC);

  return Change;
}

Status ChangeParaOfNFPC(NCAction *NFCA, PredKnowledge *PC)
{
  PCParaLink    *PL, *PL1, *PL2;
  TypedList     *P1, *Para;
  TokenList     *Pt;
  Bool           Fact, ChangePC;
  int            i, Num;

  PL = GetParaWithFactNFFact(TRUE, NFCA, PC);

  if (PL == NULL) return ERROR;

  Num = NumParaOfPred(PC->PredNo);
  Para = P1 = (TypedList *) calloc(Num, sizeof(TypedList));
  for (i = 0; i < Num; P1++,i++) P1->VList.NumValue = 0;

  Fact = TRUE;
  for (PL1 = PL; PL1 != NULL; PL1 = PL2) {
    PL2 = PL1->next;

    Fact = Fact && PL1->Fact;

    P1 = Para;
    for (Pt = PL1->Para; Pt != NULL; P1++,Pt=Pt->next)
      MergeTwoVLists(&(P1->VList), &(Pt->VList));

    FreeTokenList(PL1->Para);  free(PL1);
  }

  ChangePC = ChangeParaOfPredByTypedList(PC, Para);

  FreeTypedArray(Num, Para);

  PC->Fact = Fact;

  return ChangePC;
}

Status ChangeParaOfNFAction(NCAction *NFCA, ActKnowledge *ActK)
{
  PredKnowledge *PC;
  Bool          Change, ChangePC, ChangeAct;

  Change = FALSE;
  ChangeAct = TRUE;
  while (ChangeAct) {
    ChangeAct = FALSE;
    for (PC = ActK->PC; PC != NULL; PC = PC->next)
      if (!InstancePC(PC)) {
         ChangePC = ChangeParaOfNFPC(NFCA, PC);

         if (ChangePC == ERROR) return ERROR;

         Change = Change || ChangePC;
         ChangeAct = ChangeAct || ChangePC;
      }
  }

  return Change;
}

void LeftOneValueForEachPara(int Num1, TypedList *Para1, PredKnowledge *PC)
{
  TypedList *Pt1;
  VList     *Pt2;
  int       i, Num2;

  Num2 = NumParaOfPred(PC->PredNo);
  Pt1 = PC->Para;
  for (i = 0; i < Num2; i++,Pt1++)
    while (Pt1->VList.NumValue > 1) {
      Pt2 = Pt1->VList.List;
      Pt1->VList.List = Pt2->next;

      Pt1->VList.NumValue--;
      free(Pt2);
    }

  ChangePara1ByPara2(Num1, Para1, Num2, PC->Para);
}

Bool CopyTwoTypedLists(int Num, TypedList *Para1, TypedList *Para2)
{
  Bool Change;
  int  i;

  Change = FALSE;
  for (i = 0; i < Num; i++,Para1++,Para2++)
    if (!EqualTwoVLists(&(Para1->VList), &(Para2->VList))) {
       CopyValueList(&(Para1->VList), &(Para2->VList));
       Change = TRUE;
    }

  return Change;
}

Bool CopyTokenListIntoTypeList(TypedList *Para1, TokenList *Para2)
{
  TokenList *Pt;
  Bool      Change;

  Change = FALSE;
  for (Pt = Para2; Pt != NULL; Para1++,Pt=Pt->next)
    if (!EqualTwoVLists(&(Para1->VList), &(Pt->VList))) {
       CopyValueList(&(Para1->VList), &(Pt->VList));
       Change = TRUE;
    }

  return Change;
}

void InstanceTokenListByTypedList(TokenList *Pt, int Num, TypedList *Para)
{
  TypedList *Pt1;
  int       i;

  for (Pt = Pt->next; Pt != NULL; Pt = Pt->next) {
    i = Pt->VList.ParaIdx;
    if (0 <= i && i < Num) {
       Pt1 = Para + i;
       if (Pt->VList.NumValue != Pt1->VList.NumValue)
          CopyValueList(&(Pt->VList), &(Pt1->VList));
    }
  }
}
